package com.nervenets.web.controller.handler.user.wealth;

import com.nervenets.utils.JodaUtils;
import com.nervenets.web.controller.Global;
import com.nervenets.web.controller.handler.Handler;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.enumeration.*;
import com.nervenets.web.hibernate.domain.film.Movie;
import com.nervenets.web.hibernate.domain.user.Order;
import com.nervenets.web.hibernate.domain.user.User;
import com.nervenets.web.rabbitmq.FlowMessage;
import com.nervenets.web.rabbitmq.FlowType;
import org.weixin4j.pay.WXPay;

import javax.servlet.http.HttpServletRequest;

public class UserPayHandler extends Handler<UserPayParams> {
    @Override
    public String handle(UserPayParams params, HttpServletRequest request) throws Exception {
        final long userId = params.getUserId();
        final User user = userDao.findById(params.getUserId(), User.class);

        if (OrderType.movie.equals(params.getOrderType()) && 0 == user.getInviteUserId()) {
            if (0 == user.getInviteUserId() && null == params.getInviteCode()) {
                return errorMessage(MessageCode.code_444, "请填写推荐码");
            }
            User codeUser = userDao.getUserByCode(params.getInviteCode());
            if (null == codeUser) return errorMessage(MessageCode.code_444, "推荐码不合法，不存在！");

            if (codeUser.getId() == params.getUserId()) {
                return errorMessage(MessageCode.code_444, "不能填写自己的推荐码作为推荐码");
            }

            user.setInviteUserId(codeUser.getId());
            user.setTeamUserId(codeUser.getInviteUserId());
            userDao.saveOrUpdate(user);
            globalService.clearRedisUserStored(userId);
        }

        if (PayType.surplus.equals(params.getPayType())) {
            if (params.getSurplus() <= 0) return errorMessage(MessageCode.code_444, "请输入抵扣额度");

            long money = 0;
            long priceOfUnit = 0;
            long deposit = 0;
            long adminId = 0;
            FlowType flowType = null;
            switch (params.getOrderType()) {
                case movie:
                    final Movie movie = userDao.findById(params.getUnionId(), Movie.class);
                    if (null == movie) return errorMessage(MessageCode.code_404, "影片不存在");
                    if (MovieStatus.preheating.equals(movie.getStatus()))
                        return errorMessage(MessageCode.code_444, "预热中的项目暂时不能购买");
                    if (movie.getStatus().ordinal() > MovieStatus.ing.ordinal())
                        return errorMessage(MessageCode.code_444, "该影片停售或已售光");
                    adminId = movie.getUserId();
                    if (params.isOfflinePay()) {
                        deposit = movie.getInfo().getDeposit();
                        if (0 == deposit) return errorMessage(MessageCode.code_444, "该影片不支持线下支付");
                        money = deposit;
                    } else {
                        money = movie.getPriceOfUnit() * params.getNumber();
                    }
                    priceOfUnit = movie.getPriceOfUnit();
                    flowType = FlowType.mvPaid;

                    break;
                case recharge:
                    return errorMessage(MessageCode.code_444, "充值不支持余额抵扣");
            }
            long finalMoney = money;
            FlowType finalFlowType = flowType;
            long finalPriceOfUnit = priceOfUnit;
            long finalDeposit = deposit;
            long finalAdminId = adminId;
            return (String) redisSyncLocker.keyLock(String.format(Global.Constants.REDIS_USER_WEALTH_LOCK, userId), o -> {
                long surplus = globalService.getUserWealthOfMoney(userId, WealthType.money);
                if (surplus - finalMoney < 0) return errorMessage(MessageCode.code_410, new Model(finalMoney, surplus));

                Order order = null;
                if (params.getOrderId() > 0) {
                    order = userDao.findByIdIgnoreRemoved(params.getOrderId(), Order.class);
                }

                if (null == order) {
                    order = new Order(params.getOrderType(), params.getPayType(), userId, 0, params.getSurplus());
                } else {
                    order.setPayType(params.getPayType());
                    order.getExtra().setSurplus(params.getSurplus());
                }
                if (!OrderStatus.init.equals(order.getStatus())) {
                    return errorMessage(MessageCode.code_444, "该订单已经支付或过期，请重新下单！");
                }
                order.setOfflinePay(params.isOfflinePay());
                order.setUnionId(params.getUnionId());
                order.setAdminId(finalAdminId);
                order.getExtra().setPriceOfUnit(finalPriceOfUnit);
                order.getExtra().setNumber(params.getNumber());
                order.getExtra().setName(params.getName());
                order.getExtra().setMobile(params.getMobile());
                order.getExtra().setAddress(params.getAddress());
                order.getExtra().setRemark(params.getRemark());
                order.setStatus(OrderStatus.paid);
                order.setPayTime(JodaUtils.getTimestamp());
                if (params.isOfflinePay()) {
                    order.getExtra().setDeposit(finalDeposit);
                    order.getExtra().setTailConfirmTime(0);
                    order.setStatus(OrderStatus.tailConfirm);
                }
                userDao.saveOrUpdate(order);
                messageProducer.flow(new FlowMessage(params.getUserId(), finalFlowType, getIp(request), order.getId(), new KeyValue("detail", "余额抵扣购买")));
                //globalService.addTotalDeal(JodaUtils.getStartOfToday(), finalMoney);
                return successMessage(null, new KeyValue("orderId", order.getId()));
            }, null);
        }

        long money = 0;
        long orderId = 0;
        long adminId = 0;
        String orderNumber = "";
        String productName = "";
        switch (params.getOrderType()) {
            case movie:
                final Movie movie = userDao.findById(params.getUnionId(), Movie.class);
                if (null == movie) return errorMessage(MessageCode.code_404, "影片不存在");
                if (MovieStatus.preheating.equals(movie.getStatus()))
                    return errorMessage(MessageCode.code_444, "预热中的项目暂时不能购买");
                if (movie.getStatus().ordinal() > MovieStatus.ing.ordinal())
                    return errorMessage(MessageCode.code_444, "该影片停售或已售光");
                adminId = movie.getUserId();

                if (params.isOfflinePay()) {
                    final long deposit = movie.getInfo().getDeposit();
                    if (0 == deposit) return errorMessage(MessageCode.code_444, "该影片不支持线下支付");
                    money = deposit - params.getSurplus();
                } else {
                    money = movie.getPriceOfUnit() * params.getNumber() - params.getSurplus();
                }

                Order order = null;
                if (params.getOrderId() > 0) {
                    order = userDao.findByIdIgnoreRemoved(params.getOrderId(), Order.class);
                }
                if (null == order) {
                    order = new Order(params.getOrderType(), params.getPayType(), userId, money, params.getSurplus());
                }
                if (!OrderStatus.init.equals(order.getStatus())) {
                    return errorMessage(MessageCode.code_444, "该订单已经支付或过期，请重新下单！");
                }
                order.setOfflinePay(params.isOfflinePay());
                if (params.isOfflinePay()) {
                    order.getExtra().setDeposit(movie.getInfo().getDeposit());
                    order.getExtra().setTailConfirmTime(0);
                }
                order.setUnionId(params.getUnionId());
                order.setAdminId(adminId);
                order.getExtra().setPriceOfUnit(movie.getPriceOfUnit());
                order.getExtra().setNumber(params.getNumber());
                order.getExtra().setName(params.getName());
                order.getExtra().setMobile(params.getMobile());
                order.getExtra().setAddress(params.getAddress());
                order.getExtra().setRemark(params.getRemark());
                order.setCreateTime(JodaUtils.getTimestamp());
                userDao.saveOrUpdate(order);

                orderId = order.getId();
                orderNumber = Global.OrderNumber.getMB(orderId);
                productName = movie.getTitle();

                break;
            case recharge:
                if (params.getSurplus() > 0) return errorMessage(MessageCode.code_444, "充值不支付余额抵扣");
                order = null;
                if (params.getOrderId() > 0) {
                    order = userDao.findByIdIgnoreRemoved(params.getOrderId(), Order.class);
                }
                if (null == order) {
                    order = new Order(params.getOrderType(), params.getPayType(), userId, params.getNumber(), params.getSurplus());
                }
                order.setCreateTime(JodaUtils.getTimestamp());
                userDao.saveOrUpdate(order);

                money = params.getNumber();
                orderId = order.getId();
                orderNumber = Global.OrderNumber.getRecharge(orderId);
                productName = "账号充值";
                break;
        }
        switch (params.getPayType()) {
            case surplus:
                return errorMessage(MessageCode.code_444, "暂不支持余额抵扣！");
            case wxpay:
                return wxPay(orderId, productName, money, orderNumber, request);
            //return errorMessage(MessageCode.code_444, "暂不支持微信支付！");
            case alipay:
                return aliPay(orderId, productName, money, orderNumber, request);
            //return errorMessage(MessageCode.code_444, "暂不支持支付宝支付！");
        }
        return errorMessage(MessageCode.code_444);
    }

    @Override
    public String result() {
        return successMessage(new WXPay("appId", "ticket", "prepayId", "url", "paternerKey"));
    }

    class Model {
        private long total;
        private long surplus;

        public Model(long total, long surplus) {
            this.total = total;
            this.surplus = surplus;
        }
    }
}
